#pragma once
#include "Symbol/TypeSymbol.hpp"
#include "Syntax/Kind.hpp"

#include <map>
#include <memory>
#include <vector>

enum class BoundUnaryOperatorKind : int
{
    Error,
    Identity,
    Negation,
    OnesComplement,
    LogicalNegation
};

class BoundUnaryOperator;
typedef std::shared_ptr<BoundUnaryOperator> SharedBoundUnaryOperator;

class BoundUnaryOperator
{
public:
    BoundUnaryOperator(SyntaxKind syntaxKind, BoundUnaryOperatorKind kind, SharedTypeSymbol operandType)
        : BoundUnaryOperator(syntaxKind, kind, operandType, operandType)
    {
    }

    BoundUnaryOperator(SyntaxKind syntaxKind, BoundUnaryOperatorKind kind, SharedTypeSymbol operandType, SharedTypeSymbol resultType)
        : SyntaxKindTo(syntaxKind), Kind(kind), OperandType(operandType), Type(resultType)
    {
    }

public:
    SyntaxKind             SyntaxKindTo;
    BoundUnaryOperatorKind Kind;

    SharedTypeSymbol OperandType;
    SharedTypeSymbol RightTye;
    SharedTypeSymbol Type;

private:
    static std::vector<SharedBoundUnaryOperator> _operators;

public:
    static SharedBoundUnaryOperator Bind(SyntaxKind syntaxKind, SharedTypeSymbol operandType)
    {
        for (auto op : _operators)
        {
            if (op->SyntaxKindTo == syntaxKind && op->OperandType == operandType)
                return op;
        }

        return nullptr;
    }
    std::string GetTypeName() const { return this->KindAllName[this->Kind]; }

private:
    static std::map<BoundUnaryOperatorKind, std::string> KindAllName;
};
